import 'dart:async';
import 'dart:io';

import 'package:flutter/material.dart';
import 'package:flutter_client_sse/flutter_client_sse.dart';
import 'package:get/get.dart';
import 'package:o2oa_all_platform/common/extension/index.dart';
import 'package:speech_to_text/speech_to_text.dart';

import '../../../common/api/index.dart';
import '../../../common/models/ai/index.dart';
import '../../../common/models/meeting/meeting_info.dart';
import '../../../common/models/orgs/o2_person.dart';
import '../../../common/models/process/task_data.dart';
import '../../../common/style/icon_font.dart';
import '../../../common/utils/event_bus.dart';
import '../../../common/utils/loading.dart';
import '../../../common/utils/log_util.dart';
import '../../../common/utils/o2_api_manager.dart';
import '../../../common/utils/o2_file_path_util.dart';
import '../../../common/utils/o2_http_client.dart';
import '../../../common/utils/o2_utils.dart';
import '../../../common/values/file_icon.dart';
import '../../../common/values/o2.dart';
import '../../../common/widgets/assets_image_view.dart';
import '../../../common/widgets/o2_stateless_widget.dart';
import '../../common/inner_webview/view.dart';
import '../../common/portal/view.dart';
import '../../common/process_webview/index.dart';
import '../../home/contact/person/view.dart';
import '../calendar/create_calendar_event/index.dart';
import '../meeting/meeting_detail/view.dart';
import 'ai_search/view.dart';
import 'index.dart';

class AiController extends GetxController {
  AiController();

  final state = AiState();
  final eventBus = EventBus();
  //搜索
  final List<AIClueInfo> clueListCache = [];
  // 聊天输入
  final FocusNode chatInputNode = FocusNode();
  final ScrollController chatInputScrollController = ScrollController();
  final TextEditingController chatInputController = TextEditingController();
  // 聊天列表滚动控制器
  final ScrollController msgListScrollController = ScrollController();
  final List<AIGenerateTypeInfo> typeList = [
    AIGenerateTypeInfo(
        name: '自动',
        key: 'auto',
        iconClass: 'ooicon-networking_click',
        desc: 'AI根据你的问题自动挑最合适的'),
    AIGenerateTypeInfo(
        name: '聊天',
        key: 'chat',
        iconClass: 'ooicon-message',
        desc: '直接跟AI聊天，有问有答'),
    AIGenerateTypeInfo(
        name: '任务', key: 'mcp', iconClass: 'ooicon-renwu', desc: 'AI帮你完成OA任务'),
    AIGenerateTypeInfo(
        name: '知识库',
        key: 'rag',
        iconClass: 'ooicon-canyue',
        desc: 'AI结合系统文档数据来回答'),
  ];
  final attachmentTypeList = [
    'doc',
    'docx',
    'wps',
    'ppt',
    'pptx',
    'pub',
    'vsd',
    'xls',
    'xlsx',
    'html',
    'htm',
    'txt',
    'md',
    'pdf',
    'ofd'
  ];
  // final speech2Text = Speech2TextHelper();

  /// 在 onInit() 之后调用 1 帧。这是进入的理想场所
  @override
  void onReady() {
    initAll();
    // eventBus.on(EventBus.onnxStatusMsg, 'ai', (s) {
    //   if (s is OnnxModelStatus) {
    //     state.speechStatus.value = s;
    //     if (s == OnnxModelStatus.done) {
    //       initRecorder();
    //     }
    //   }
    // });
    super.onReady();
  }

  Future<void> initAll() async {
    state.generateType.value = typeList[0];
    await Future.wait([loadConfig(), loadClueList(), initRecorder()]);
    OLogger.d('---> 1  ${DateTime.now()}');
    // speech2Text.initInstance();
  }

  @override
  void onClose() {
    // eventBus.off(EventBus.onnxStatusMsg, 'ai');
    // speech2Text.destroy();
    super.onClose();
  }

  Future<void> loadConfig() async {
    OLogger.d('start config ${DateTime.now()}');
    final config = await AIAssembleControlService.to.config();
    if (config == null) {
      OLogger.e('AI 配置读取失败！！！！！！！！！！！');
      Loading.toast('模块加载失败！');
      Get.back();
      return;
    }
    state.config.value = config;
    OLogger.d('start config ${DateTime.now()}');
  }

  Future<void> loadClueList() async {
    OLogger.d('start Clue ${DateTime.now()}');
    clueListCache.clear();
    final list = await AIAssembleControlService.to.clueListByPage(1);
    state.clueList.clear();
    if (list != null) {
      clueListCache.addAll(list);
      _setClueList(clueListCache);
    }
    OLogger.d('start Clue ${DateTime.now()}');
  }

  _setClueList(List<AIClueInfo> list) {
    final a = list.map((c) {
      final r = _clueTime2GroupTag(c);
      c.groupTag = r.$1;
      c.groupOrder = r.$2;
      return c;
    }).toList();
    state.clueList.addAll(a);
  }


  (String, int) _clueTime2GroupTag(AIClueInfo clue) {
    if (clue.createDateTime != null && clue.createDateTime!.isNotEmpty) {
      final time = DateTime.tryParse(clue.createDateTime!);
      if (time != null) {
        var now = DateTime.now();
        var days = now.difference(time).inDays;
        if (now.year == time.year &&
            now.month == time.month &&
            now.day == time.day) {
          return ('ai_clue_time_format_today'.tr, 3);
        } else if (days < 7) {
          return ('ai_clue_time_format_week'.tr, 2);
        } else if (days < 31) {
          return ('ai_clue_time_format_month'.tr, 1);
        }
      }
    }
    return ('ai_clue_time_format_long'.tr, 0);
  }

  Future<void> loadChatList() async {
    if (state.currentClue.value == null ||
        state.currentClue.value?.id == null) {
      return;
    }
    Loading.show();
    OLogger.d('start chat ${DateTime.now()}');
    final list = await AIAssembleControlService.to
        .clueChatListByPage(1, state.currentClue.value!.id!);
    state.chatInfoList.clear();
    OLogger.d('start chat ${DateTime.now()}');
    if (list != null) {
      Loading.dismiss();
      state.chatInfoList.addAll(list);
      _delayScorllToBottom();
    }
  }

  /// 针对UI动画
  void _delayScorllToBottom() {
    if (state.chatInfoList.isEmpty) {
      return;
    }
    // 滚动底部 这里需要等待刷新页面后才能滚动
    Future.delayed(const Duration(milliseconds: 200), () {
      msgListScrollController.animateTo(
          msgListScrollController.position.maxScrollExtent,
          duration: const Duration(milliseconds: 200),
          curve: Curves.easeInOut);
    });
  }

  void clickSendMsg() {
    final text = chatInputController.text;
    if (text.trim().isEmpty) {
      Loading.showError('ai_input_hint'.tr);
      return;
    }
    _sendMsg(text);
  }

  /// 给 AI 发送消息
  void _sendMsg(String text) {
    if (state.aiResponsing) {
      OLogger.e('正在响应中。。。。。。');
      return;
    }
    // 处理附件
    if (state.chatAttachmentList.isNotEmpty) {
      // 判断是否有正在上传的附件
      bool hasLoading = false;
      for (var element in state.chatAttachmentList.values) {
        if (element.fileId == null || element.fileId?.isEmpty == true) {
          hasLoading = true;
        }
      }
      if (hasLoading) {
        Loading.toast('ai_chat_attachment_loading'.tr);
        return;
      }
    }
    state.aiResponsing = true; // 开始
    List<String> attachmentIds = [];
    // 附件
    if (state.chatAttachmentList.isNotEmpty) {
      attachmentIds =
          state.chatAttachmentList.values.map((e) => e.fileId!).toList();
    }
    final chatinfo = AIChatInfo(id: '', input: text);
    if (state.chatAttachmentList.isNotEmpty) {
      chatinfo.materialIdList = attachmentIds;
    }
    state.chatInfoList.add(chatinfo);
    _delayScorllToBottom();
    // 开始发送 SSE
    final post = AIChatPost(input: text);
    if (state.generateType.value != null &&
        state.generateType.value?.key != null &&
        state.generateType.value?.key != 'auto') {
      post.generateType = state.generateType.value?.key;
    }
    if (state.currentClue.value != null &&
        state.currentClue.value?.id != null) {
      post.clueId = state.currentClue.value?.id;
    }
    if (state.chatAttachmentList.isNotEmpty) {
      post.materialIdList = attachmentIds;
    }
    OLogger.d('发送 SSE ${post.toJson()}');
    AIAssembleControlService.to.clueChatSSE(post, receiveSSE);
    chatInputController.text = '';
    state.chatAttachmentList.clear();
  }

  /// 接收到SSE 消息后处理具体业务
  void receiveSSE(SSEModel model) {
    if (model.event == 'status') {
      final data = O2Utils.parseStringToJson(model.data ?? '{}');
      if (data['clueId'] != null &&
          data['id'] != null &&
          state.chatInfoList.isNotEmpty) {
        // 这条数据是 AIChatInfo
        final info = state.chatInfoList.last;
        info.id = (data['id'] as String);
        info.clueId = (data['clueId'] as String);
        if (data['generateType'] != null) {
          info.generateType = (data['generateType'] as String);
        }
        state.chatInfoList[state.chatInfoList.length - 1] = info;
        if (state.currentClue.value == null) {
          state.currentClue.value = AIClueInfo(id: info.clueId);
        }
      }
    } else if (model.event == 'message') {
      if (model.data?.trim() == O2.SSE_DONE) {
        state.aiResponsing = false; // 结束
        loadClueList(); // 更新会话列表
      } else {
        final data = O2Utils.parseStringToJson(model.data ?? '{}');
        AIChatContent content = AIChatContent.fromJson(data);
        if (content.choices != null &&
            content.choices!.isNotEmpty &&
            state.chatInfoList.isNotEmpty) {
          final info = state.chatInfoList.last;
          String choicesText = content.choices![0].delta?.content ?? '';
          if (choicesText.trim().isEmpty) {
            choicesText = content.choices![0].message?.content ?? '';
          }
          info.content = '${info.content ?? ''}$choicesText';
          state.chatInfoList[state.chatInfoList.length - 1] = info;
          //  if (choicesText.contains('\$\$mcp\$\$')) {
          if (info.generateType == 'mcp') {
            // 结束
            state.aiResponsing = false;
            loadClueList(); // 更新会话列表
          }
          _delayScorllToBottom();
        }
      }
    }
  }

  /// 新建对话
  void clickNewClue() {
    state.chatInfoList.clear();
    state.currentClue.value = null;
    state.title = '';
    state.generateType.value = typeList[0];
    state.chatAttachmentList.clear();
    state.aiResponsing = false;
    AIAssembleControlService.to.closeSSE();
  }

  Future<void> clickSearchClue() async {
    final clue = await AiSearchPage.openSearch(clueListCache);
    if (clue != null && clue is AIClueInfo) {
      clickLoadClue(clue);
    }
  }

  /// 点击列示对话
  void clickLoadClue(AIClueInfo info) {
    state.currentClue.value = info;
    state.title = info.title ?? '';
    loadChatList();
  }

  /// 选择AI 模式
  void clickChooseGenerateType() {
    final context = Get.context;
    if (context == null) {
      return;
    }
    List<Widget> list = typeList.map((t) {
      return ListTile(
          onTap: () {
            Navigator.pop(context);
            state.generateType.value = t;
          },
          title: Row(
            children: [
              Icon(O2IconFont.ooiconFont(t.iconClass ?? ''), size: 20),
              const SizedBox(width: 5),
              Text('${t.name} | ${t.desc}'),
            ],
          ));
    }).toList();
    O2UI.showBottomSheetWithCancel(context, list);
  }

  /// 点击切换语音输入
  void clickVoiceBtn() {
    state.inputTypeVoice = !state.inputTypeVoice;
    if (state.inputTypeVoice) {
      chatInputNode.unfocus(); // 关闭输入法
    } else {
      chatInputNode.requestFocus(); // 开启输入法
    }
    _delayScorllToBottom();
  }

  /// 下载安装语音转文字模型
  // Future<void> clickCheckOnnx() async {
  //   final status = await OnnxModelDownloader().checkStatus();
  //   if (status == OnnxModelStatus.notInstall) {
  //     _startInstallOnnx();
  //   } else if (status == OnnxModelStatus.fail) {
  //     Loading.toast('安装失败！');
  //   }
  // }

  // void _startInstallOnnx() {
  //   final context = Get.context;
  //   if (context == null) {
  //     return;
  //   }
  //   O2UI.showConfirm(context, '确定要下载安装语音识别扩展包（大小：110M）吗？',
  //       okPressed: () => OnnxModelDownloader().downloadModelFile());
  // }

  String _lastWords = '';
  bool _startInit = false;
  final SpeechToText _speechToText = SpeechToText();
  Future<void> initRecorder() async {
    if (_startInit) {
      OLogger.e('正在初始化中...');
      return;
    }
    _startInit = true;
    try {
      state.speechEnabled = await _speechToText.initialize();
      if (Platform.isAndroid) { // 国产 Android 都不支持。。。
        state.speechEnabled = false;
      }
    } on Exception catch (e) {
      OLogger.e('$e');
    }
    _startInit = false;
  }

  Future<void> startRecorder() async {
    if (state.aiResponsing) {
      OLogger.e('正在响应中2。。。。。。');
      return;
    }
    // 检查录音权限
    var isPermission = await O2Utils.microphonePermission();
    if (!isPermission) {
      OLogger.e('没有权限，无法录音');
      Loading.showError('im_chat_error_need_record_permission'.tr);
      return;
    }
    _lastWords = '';
    await _speechToText.listen(onResult: (result)=> {
      _lastWords = result.recognizedWords
    });
  }

  Future<void> stopRecorder() async {
    await _speechToText.stop();
    await Future.delayed(const Duration(milliseconds: 300));
    if (_lastWords.trim().isNotEmpty) {
      _sendMsg(_lastWords);
    } else {
      Loading.toast('抱歉，没有听清！');
    }
  }

  void clickAttachmentItem(AIFileUploadItem item) {
    if (item.fileId != null && item.fileId!.isNotEmpty) {
      // 已经上传完成的点击删除
      String key = item.fileLocalPath ?? '';
      if (key.isNotEmpty) {
        state.chatAttachmentList.remove(key);
      }
    }
  }

  /// 选择附件上传
  void clickAddAttachment() {
    if (state.chatAttachmentList.length >= 5) {
      Loading.toast('ai_attachment_max_number'.tr);
      return;
    }
    List<String> exts = attachmentTypeList;
    if (Platform.isAndroid) {
      exts.addAll(['png', 'jpeg', 'jpg']);
    }
    O2Utils.pickerFileOrImage((paths) {
      if (paths.isNotEmpty && paths[0] != null) {
        _uploadAttachment(paths[0]!);
      }
    }, allowMultiple: false, allowedExtensions: attachmentTypeList);
  }

  Future<void> _uploadAttachment(String path) async {
    if (state.chatAttachmentList.containsKey(path)) {
      return;
    }
    AIFileUploadItem item =
        AIFileUploadItem(fileLocalPath: path, ext: path.fileNameExtension());
    state.chatAttachmentList[path] = item;
    OLogger.d('开始上传附件 path: $path');
    final id = await AIAssembleControlService.to.uploadAttachment(File(path));
    if (id != null && id.id != null) {
      var replyItem = state.chatAttachmentList[path];
      if (replyItem != null) {
        replyItem.fileId = id.id;
        state.chatAttachmentList[path] = replyItem;
      }
    } else {
      state.chatAttachmentList.remove(path);
    }
  }

  Future<void> clickOpenAttachmentList(AIChatInfo info) async {
    if (info.materialIdList != null && info.materialIdList!.isNotEmpty) {
      Loading.show();
      final list = await AIAssembleControlService.to
          .attachmentList(info.materialIdList!);
      if (list != null) {
        Loading.dismiss();
        _openAttachmentList(list);
      }
    }
  }

  void _openAttachmentList(List<AIChatAttachmentInfo> list) {
    final context = Get.context;
    if (context == null) {
      return;
    }
    O2UI.showBottomSheetLongList(
        context,
        list
            .map((e) => ListTile(
                  leading: AssetsImageView(
                      FileIcon.getFileIconAssetsNameByExtension(
                          e.extension ?? ''),
                      width: 32,
                      height: 32),
                  title: Text(e.name ?? '未知'),
                  trailing: Text('${e.length?.friendlyFileLength()}',
                      style: const TextStyle(fontSize: 12.0)),
                  onTap: () {
                    Navigator.pop(context);
                    _downloadAttachment(e);
                  },
                ))
            .toList(),
        title: 'bbs_subject_attachment_title'.tr);
  }

  Future<void> _downloadAttachment(AIChatAttachmentInfo info) async {
    Loading.show();
    String? filePath =
        await O2FilePathUtil.getAIFileDownloadLocalPath(info.id!, info.name!);
    if (filePath == null || filePath.isEmpty) {
      Loading.showError('ai_file_download_no_path'.tr);
      return;
    }
    var file = File(filePath);
    if (file.existsSync()) {
      Loading.dismiss();
      O2Utils.openLocalFile(filePath, info.name!);
    } else {
      // 下载附件
      var donwloadUrl =
          AIAssembleControlService.to.getAIAttachmentURL(info.id!);
      try {
        await O2HttpClient.instance.downloadFile(donwloadUrl, filePath);
        Loading.dismiss();
        O2Utils.openLocalFile(filePath, info.name!);
      } on Exception catch (e) {
        Loading.showError(e.toString());
      }
    }
  }

  void clickEnterPerson(O2Person person) {
    PersonPage.openPersonInfo(person);
  }

  // 确认创建会议
  Future<void> clickSubmitMeeting(MeetingInfoForAIResponse meetingRes) async {
    Loading.show();
    final MeetingInfoModel meetingInfo = MeetingInfoModel();
    meetingInfo.subject = meetingRes.subject;
    meetingInfo.room = meetingRes.roomObj?.id;
    meetingInfo.startTime = meetingRes.startTime;
    meetingInfo.completedTime = meetingRes.completedTime;
    meetingInfo.applicant = O2ApiManager.instance.o2User?.distinguishedName;
    meetingInfo.invitePersonList = meetingRes.inviteObjList ?? [];
    final id = await MeetingAssembleService.to.saveMeeting(meetingInfo);
    if (id != null) {
      Loading.dismiss();
      final info = state.chatInfoList.last;
      final AIChatInfo extraBody = AIChatInfo();
      extraBody.id = info.id;
      extraBody.extra = {'meetingId': id.id};
      final result = await AIAssembleControlService.to
          .writeChatMsgExtra(extraBody.toJson());
      if (result != null) {
        OLogger.d(
            'writeChatMsgExtra ${extraBody.toJson()} result: ${result.toJson()}');
      }
      info.extra = {'meetingId': id.id};
      state.chatInfoList[state.chatInfoList.length - 1] = info;
    }
  }

  // 查看会议详情
  void clickViewMeeting(String id) {
    MeetingDetailPage.openMeeting(id);
  }

  void clickViewTask(TaskData task) {
    ProcessWebviewPage.open(task.work ?? '', title: task.title ?? '');
  }

  void clickViewPortal(String portalId, {String? pageId, String? parameters}) {
    PortalPage.open(portalId, pageId: pageId, portalParameters: parameters);
  }

  Future<void> clickViewCalendarEventInfo(String eventId) async {
    if (eventId.isEmpty) {
      return;
    }
    Loading.show();
    final event = await CalendarAssembleControlService.to.getEvent(eventId);
    if (event != null) {
      Loading.dismiss();
      CreateCalendarEventPage.openUpdate(event);
    }
  }

  void clickViewWork(String workId, {String? title}) {
    ProcessWebviewPage.open(workId, title: title ?? '');
  }

  void clickOpenUrl(String url) {
    if (url.isURL) {
      InnerWebviewPage.open(url);
    } else {
      OLogger.e('无法打开 url $url');
    }
  }
}
